﻿#region License
// MIT License
//
// Copyright(c) 2019-2025 ZhangYu
// https://gitee.com/zhangyu800/litebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#endregion
#region Intro
// Purpose: Reflection Optimize Performance
// Author: ZhangYu
// CreateDate: 2019-11-22
// LastModifiedDate: 2025-02-10
#endregion
// 是否使用快速反射
namespace LiteByte.Reflection {

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Reflection;
    using LiteByte.Common;

    /// <summary>
    /// <para>LBReflectionUtil</para>
    /// <para> 反射工具 | Reflection tool</para>
    /// </summary>
    public static class ReflectionUtil {

        #region 创建对象实例 | Create instance
        /// <summary> 创建对象 </summary>
        public static object CreateObject(Type type, params object[] args) {
            if (type.IsValueType) return CreateValueType(type);
            if (type.IsArray) return CreateArray(type.GetElementType(), (int)args[0]);
            if (type.IsGenericType) {
                Type typeDefine = type.GetGenericTypeDefinition();
                Type[] generics = type.GetGenericArguments();
                if (typeDefine == typeof(List<>)) return CreateList(generics[0], (int)args[0]);
                if (typeDefine == typeof(Dictionary<,>)) return CreateHashMap(generics[0], generics[1], (int)args[0]);
            }
            return Activator.CreateInstance(type);
        }

        /// <summary> 创建基本值类型 </summary>
        public static object CreateValueType(Type type) {
            TypeCode typeCode = Type.GetTypeCode(type);
            switch (typeCode) {
                case TypeCode.Boolean: return false;
                case TypeCode.Char: return default(char);
                case TypeCode.SByte: return default(sbyte);
                case TypeCode.Byte: return default(byte);
                case TypeCode.Int16: return default(short);
                case TypeCode.UInt16: return default(ushort);
                case TypeCode.Int32: return 0;
                case TypeCode.UInt32: return default(uint);
                case TypeCode.Int64: return 0L;
                case TypeCode.UInt64: return default(ulong);
                case TypeCode.Single: return 0f;
                case TypeCode.Double: return 0d;
                case TypeCode.Decimal: return default(decimal);
                case TypeCode.DateTime: return default(DateTime);
                case TypeCode.String: return null;
                default: return Activator.CreateInstance(type);
            }
        }

        /// <summary> 创建数组 </summary>
        public static Array CreateArray(Type elementType, int length) {
            TypeCode typeCode = Type.GetTypeCode(elementType);
            switch (typeCode) {
                case TypeCode.Boolean: return new bool[length];
                case TypeCode.Char: return new char[length];
                case TypeCode.SByte: return new sbyte[length];
                case TypeCode.Byte: return new byte[length];
                case TypeCode.Int16: return new short[length];
                case TypeCode.UInt16: return new ushort[length];
                case TypeCode.Int32: return new int[length];
                case TypeCode.UInt32: return new int[length];
                case TypeCode.Int64: return new long[length];
                case TypeCode.UInt64: return new ulong[length];
                case TypeCode.Single: return new float[length];
                case TypeCode.Double: return new double[length];
                case TypeCode.Decimal: return new decimal[length];
                case TypeCode.DateTime: return new DateTime[length];
                case TypeCode.String: return new string[length];
                default: return Array.CreateInstance(elementType, length);
            }
        }

        /// <summary> 创建List&lt;T&gt; </summary>
        public static IList CreateList(Type genericType, int count) {
            TypeCode typeCode = Type.GetTypeCode(genericType);
            switch (typeCode) {
                case TypeCode.Boolean: return new List<bool>(count);
                case TypeCode.Char: return new List<char>(count);
                case TypeCode.SByte: return new List<sbyte>(count);
                case TypeCode.Byte: return new List<byte>(count);
                case TypeCode.Int16: return new List<short>(count);
                case TypeCode.UInt16: return new List<ushort>(count);
                case TypeCode.Int32: return new List<int>(count);
                case TypeCode.UInt32: return new List<int>(count);
                case TypeCode.Int64: return new List<long>(count);
                case TypeCode.UInt64: return new List<ulong>(count);
                case TypeCode.Single: return new List<float>(count);
                case TypeCode.Double: return new List<double>(count);
                case TypeCode.Decimal: return new List<decimal>(count);
                case TypeCode.DateTime: return new List<DateTime>(count);
                case TypeCode.String: return new List<string>(count);
                default:
                    Type listType = typeof(List<>).MakeGenericType(genericType);
                    return (IList)Activator.CreateInstance(listType, count);
            }
        }

        /// <summary> 创建HashMap </summary>
        public static IDictionary CreateHashMap(Type keyType, Type valueType, int count) {
            switch (Type.GetTypeCode(keyType)) {
                case TypeCode.Int32:
                    switch (Type.GetTypeCode(valueType)) {
                        case TypeCode.Int32: return new Dictionary<int, int>(count);
                        case TypeCode.String: return new Dictionary<int, string>(count);
                    }
                    break;
                case TypeCode.String:
                    switch (Type.GetTypeCode(valueType)) {
                        case TypeCode.Int32: return new Dictionary<string, int>(count);
                        case TypeCode.String: return new Dictionary<string, string>(count);
                    }
                    break;
            }
            Type mapType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
            return (IDictionary)Activator.CreateInstance(mapType, count);
        }

        public static object CreateInstance(Type type) {
            return Activator.CreateInstance(type);
        }
        #endregion

        #region 获取对象的成员(字段或属性)
        private static Dictionary<Type, Dictionary<string, IMemberWrapper>> memberCache = new Dictionary<Type, Dictionary<string, IMemberWrapper>>();

        /// <summary> 获取属性包装器 </summary>
        public static IMemberWrapper GetMemberWrapper(Type type, string memberName) {
            if (type == null) throw new Exception("GetMemberWrapper: type is null");
            if (string.IsNullOrEmpty(memberName)) throw new Exception("GetMemberWrapper: memberName is null");
            // 查找类型
            Dictionary<string, IMemberWrapper> cache = null;
            if (!memberCache.TryGetValue(type, out cache)) {
                cache = new Dictionary<string, IMemberWrapper>();
                memberCache.Add(type, cache);
            }

            // 查找包装器
            IMemberWrapper wrapper = null;
            if (!cache.TryGetValue(memberName, out wrapper)) {
                MemberInfo[] members = type.GetMember(memberName, BindingFlags.Public | BindingFlags.Instance);
                if (members.Length == 0) throw new Exception($"GetMemberWrapper:{type.Name}.{memberName} not exist!");
                MemberInfo member = members[0];
                Type memberType = member.MemberType == MemberTypes.Field ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                Type wrapperType = typeof(MemberWrapper<,>).MakeGenericType(type, memberType);
                wrapper = (IMemberWrapper)Activator.CreateInstance(wrapperType, member);
                cache.Add(memberName, wrapper);
            }
            return wrapper;
        }

        private static Dictionary<Type, IMemberWrapper[]> membersCache = new Dictionary<Type, IMemberWrapper[]>();

        /// <summary> 获取属性包装器 </summary>
        public static IMemberWrapper[] GetMembersWrappers(Type type, List<FieldData> lbFields) {
            if (type == null) throw new Exception("GetMemberWrappers: type is null");
            if (lbFields == null) throw new Exception("GetMemberWrappers: lbFields is null");
            // 查找包装器
            IMemberWrapper[] wrappers = null;
            if (!membersCache.TryGetValue(type, out wrappers)) {
                wrappers = new IMemberWrapper[lbFields.Count];
                for (int i = 0; i < lbFields.Count; i++) {
                    FieldData lBField = lbFields[i];
                    string memberName = lBField.Name;
                    MemberInfo[] members = type.GetMember(memberName, BindingFlags.Public | BindingFlags.Instance);
                    if (members.Length == 0) throw new Exception($"GetMemberWrappers:{type.Name}.{memberName} not exist!");
                    MemberInfo member = members[0];
                    Type memberType = member.MemberType == MemberTypes.Field ? ((FieldInfo)member).FieldType : ((PropertyInfo)member).PropertyType;
                    Type wrapperType = typeof(MemberWrapper<,>).MakeGenericType(type, memberType);
                    wrappers[i] = (IMemberWrapper)Activator.CreateInstance(wrapperType, member);
                }
                membersCache.Add(type, wrappers);
            }
            return wrappers;
        }
        #endregion

        #region 判断类或结构体是否是默认值
        public static bool IsDefaultValue(object obj, TypeData lbType) {
            if (lbType.IsStruct) return IsStructDefault(obj, lbType);
            return obj == null;
        }

        /// <summary> 判断结构体是否为默认值(检查所有成员的值) </summary>
        private static bool IsStructDefault(object obj, TypeData lbType) {
            Type type = obj.GetType();
            List<FieldData> fields = lbType.Fields;
            IMemberWrapper[] wrappers = GetMembersWrappers(type, fields);
            for (int i = 0; i < fields.Count; i++) {
                IMemberWrapper wrapper = wrappers[i];
                FieldData field = fields[i];
                TypeData fieldLBType = field.Type;
                Type fieldType = wrapper.Type;
                object value = wrapper.GetValue(obj);
                if (fieldLBType.IsNumberType) {
                    if (!IsNumberTypeDefault(value, fieldLBType.TypeCode)) return false;
                } else if (fieldLBType.IsStruct) {
                    if (!IsStructDefault(value, fieldLBType)) return false;
                } else {
                    if (value != null) return false;
                }
            }
            return true;
        }

        private static bool IsNumberTypeDefault(object value, TypeName typeCode) {
            switch (typeCode) {
                case TypeName.Bit1: return (bool)value == false;
                case TypeName.Bit2: return (byte)value == 0;
                case TypeName.Bit3: return (byte)value == 0;
                case TypeName.Bit4: return (byte)value == 0;
                case TypeName.Bit5: return (byte)value == 0;
                case TypeName.Bit6: return (byte)value == 0;
                case TypeName.Bit7: return (byte)value == 0;
                case TypeName.Bit8: return (byte)value == 0;
                case TypeName.Bool: return (bool)value == false;
                case TypeName.Char: return (char)value == '\0';
                case TypeName.Int8: return (sbyte)value == 0;
                case TypeName.Int16: return (short)value == 0;
                case TypeName.Int32: return (int)value == 0;
                case TypeName.Int64: return (long)value == 0;
                case TypeName.UInt8: return (byte)value == 0;
                case TypeName.UInt16: return (ushort)value == 0;
                case TypeName.UInt32: return (uint)value == 0;
                case TypeName.UInt64: return (ulong)value == 0;
                case TypeName.Float16: return (Half)value == Half.Zero;
                case TypeName.Float32: return (float)value == 0f;
                case TypeName.Float64: return (double)value == 0d;
                case TypeName.VInt16: return (short)value == 0;
                case TypeName.VInt32: return (int)value == 0;
                case TypeName.VInt64: return (long)value == 0;
                case TypeName.VUInt16: return (ushort)value == 0;
                case TypeName.VUInt32: return (uint)value == 0;
                case TypeName.VUInt64: return (ulong)value == 0;
                case TypeName.Decimal: return (decimal)value == 0m;
                case TypeName.DateTime: return (DateTime)value == default(DateTime);
                default: return value == null;
            }
        }
        #endregion

        #region 清理数据
        /// <summary> 清理所有缓存的数据 | Clear all cached datas </summary>
        public static void ClearCache() {
            memberCache.Clear();
            membersCache.Clear();
        }
        #endregion

    }

}